﻿using Microsoft.CSharp;
using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Text;
using System.Web;
using System.Web.Services;
using System.Web.Services.Description;
using System.Web.Services.Protocols;

namespace WebSOAPUI.Lib
{
    public class SOAPRequest
    {
        /// <summary>
        /// Web服务调用地址
        /// </summary>
        public string EndPoint { get; set; }

        /// <summary>
        /// 调用Web服务的用户名
        /// </summary>
        public string Username { get; set; }

        /// <summary>
        /// 调用Web服务的密码
        /// </summary>
        public string Password { get; set; }

        /// <summary>
        /// SOAPAction名称
        /// <list type="string">
        /// <para>\"urn:sap-com:document:sap:soap:functions:mc-style:ZESAPWS_MM001:ZesapfunMm001\"</para>
        /// </list>
        /// </summary>
        public string SOAPAction { get; set; }

        /// <summary>
        /// 要发送的SOAP数据包
        /// </summary>
        public string SOAPData { get; set; }
    }

    public class WebServiceInfo
    {
        public string Service { get; set; }

        public string SOAPAddress { get; set; }

        public string Namespace { get; set; }

        public string Description { get; set; }

        public string WSDLUrl { get; set; }

        public List<WebServiceMethodInfo> Methods { get; set; }
    }

    public class WebServiceMethodInfo
    {
        public string MethodName { get; set; }
        public string SOAPAction { get; set; }
    }

    public class WebServiceUtils
    {
        public static string PostSOAPRequest(SOAPRequest request)
        {
            //"http://10.63.0.20:8000/sap/bc/srt/rfc/sap/zesapws_mm001/310/zesapws_mm001/zesapws_mm001"
            var req = (HttpWebRequest)WebRequest.Create(request.EndPoint);
            req.Credentials = new NetworkCredential(request.Username, request.Password);
            req.Method = "POST";
            req.UserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; MS Web Services Client Protocol 4.0.30319.18444)";
            req.ContentType = "text/xml; charset=utf-8";
            req.Headers.Add("SOAPAction", request.SOAPAction);

            var postData = Encoding.UTF8.GetBytes(request.SOAPData);
            req.ContentLength = postData.Length;
            var outStream = req.GetRequestStream();
            outStream.Write(postData, 0, postData.Length);
            using (var rsp = (HttpWebResponse)req.GetResponse())
            {
                var response = string.Empty;
                using (var sr = new StreamReader(rsp.GetResponseStream()))
                {
                    response = sr.ReadToEnd();
                }
                return response;
            }
        }

        public static WebServiceInfo ResolveServiceInfo(string wsdlData)
        {

            string @namespace = "CNOOCTempDynamic";
            try
            {
                WebServiceInfo wsInfo = null;
                var asmName = "CNOOCTempDynamic";
                var asmFileName = AppDomain.CurrentDomain.BaseDirectory + "/bin/" + asmName + ".dll";
                try
                {
                    File.Delete(asmFileName);
                } catch { }
                Assembly assembly = null;
                Type type;
                Object instance;
                MethodInfo methodInfo;

                //var wsdlFile = @"C:\Users\GJ\Desktop\document2.xml";
                //var stream = File.Open(wsdlFile, FileMode.Open, FileAccess.Read);

                var buff = Encoding.UTF8.GetBytes(wsdlData);
                var stream2 = new MemoryStream(buff);

                ServiceDescription description = ServiceDescription.Read(stream2);
                ServiceDescriptionImporter importer = new ServiceDescriptionImporter();
                importer.ProtocolName = "Soap"; //指定访问协议。
                importer.AddServiceDescription(description, "", "");//添加WSDL文档。

                CodeNamespace codeNamespace = new CodeNamespace(@namespace);
                CodeCompileUnit codeCompileUnit = new CodeCompileUnit(); //生成客户端代理类代码 
                codeCompileUnit.Namespaces.Add(codeNamespace);
                importer.Import(codeNamespace, codeCompileUnit);
                CSharpCodeProvider codeProvider = new CSharpCodeProvider();

                CompilerParameters compilerParameters = new CompilerParameters();  //设定编译参数 
                compilerParameters.GenerateExecutable = false;
                //cplist.GenerateInMemory = true; // 在内存中生成程序集
                compilerParameters.OutputAssembly = asmFileName; // 生成本地址程序集
                compilerParameters.ReferencedAssemblies.Add("System.dll");
                compilerParameters.ReferencedAssemblies.Add("System.XML.dll");
                compilerParameters.ReferencedAssemblies.Add("System.Web.Services.dll");
                compilerParameters.ReferencedAssemblies.Add("System.Data.dll");

                CompilerResults compilerResults = codeProvider.CompileAssemblyFromDom(compilerParameters, codeCompileUnit); //编译代理类 
                if (compilerResults.Errors.HasErrors)
                {
                    System.Text.StringBuilder sb = new System.Text.StringBuilder();
                    foreach (System.CodeDom.Compiler.CompilerError ce in compilerResults.Errors)
                    {
                        sb.Append(ce.ToString());
                        sb.Append(System.Environment.NewLine);
                    }
                    throw new Exception(sb.ToString());
                }
                assembly = Assembly.LoadFrom(asmFileName); // 不加.dll的后缀
                var modules = assembly.GetModules();
                wsInfo = new WebServiceInfo();
                wsInfo.Methods = new List<WebServiceMethodInfo>();
                foreach (var m in modules)
                {
                    foreach (var t in m.GetTypes().Where(it => it.IsSubclassOf(typeof(SoapHttpClientProtocol))))
                    {
                        var wsInst = Activator.CreateInstance(t);
                        if (wsInst != null)
                        {
                            var prop = t.GetProperty("Url");
                            var url = prop.GetValue(wsInst, null);
                            wsInfo.SOAPAddress = url == null ? string.Empty : url.ToString();
                        }

                        wsInfo.Service = t.Name;
                        var bindingAttrs = (WebServiceBindingAttribute[])t.GetCustomAttributes(typeof(WebServiceBindingAttribute), false);
                        if (bindingAttrs != null && bindingAttrs.Length > 0)
                        {
                            wsInfo.Service = bindingAttrs[0].Name;
                            wsInfo.Namespace = bindingAttrs[0].Namespace;
                        }
                        var methods = t.GetMethods(BindingFlags.Public | BindingFlags.Instance);
                        foreach (var method in methods)
                        {
                            var cas = (SoapDocumentMethodAttribute[])method.GetCustomAttributes(typeof(SoapDocumentMethodAttribute), false);
                            if (cas != null && cas.Length > 0)
                            {
                                var a = cas[0];
                                var wsMethodInfo = new WebServiceMethodInfo()
                                {
                                    MethodName = method.Name,
                                    SOAPAction = wsInfo.Namespace + ":" + wsInfo.Service + ":" +
                                        method.Name
                                };
                                wsInfo.Methods.Add(wsMethodInfo);
                            }
                        }
                    }
                }
                try
                {
                    File.Delete(asmFileName);
                    
                } catch { }
                return wsInfo;
            } catch (Exception ex)
            {
                throw ex;
            }
        }
    }
}